﻿/*
   Copyright 2012 University of Southampton

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Collections.Generic;
using System.Linq;
using uk.ac.soton.ses.DAL;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint;
using System.Web;
using System.Security.Principal;
using System.Data.Objects.DataClasses;
using uk.ac.soton.ses.UserControls;

namespace uk.ac.soton.ses.ExperimentsWebPart
{
    public partial class ExperimentsWebPartUserControl : UserControl
    {
        //Class used for populating the gridview
        private class GridData
        {
            
            public Experiment Experiment { get; set; }
            public ExperimentType ExperimentType { get; set; }
            public EntityCollection<ExperimentParameter> ExperimentParameters { get; set; }
            public int DataFileCount { get; set; }
            public int ParameterCount { get; set; }

            //Properties for the gridview that map to the sub-objects' properties
            public int ID { get { return Experiment.ID; } }
            public string Name { get { return Experiment.Name; } }
            public string Description { get { return Experiment.Description; } }

        }

       

        public int SelectedRowID
        {
            get
            {
                if (this.View_Experiments.SelectedIndex != -1)
                {
                    return (int)this.View_Experiments.SelectedDataKey["ID"];
                }
                else
                {
                    return -1;
                }
            }
        }

        private MaterialsMetadataContext _dbcontext = null;
        private ExperimentQuickSearch _searchControl = null;
        private const int maximumExperiments = 300;
        private bool _isInitialised = false;

        #region Page life cycle methods

        /// <summary>
        /// OnInit in ASP.NET page life cycle overridden. We add controls and events here.
        /// </summary>
        /// <param name="e">Event arguments received by events</param>
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            try
            {
                this._dbcontext = HttpContext.Current.GetMaterialsDBContext();
                this.AddControls();
                this.ConfigureEvents();

                //Allow Page_Load to databind
                this._isInitialised = true;
            }
            catch (Exception ex)
            {
                this.HandleException(ex);
            }

        }

        /// <summary>
        /// Page_Load in ASP.NET page life cycle. We databind controls here.
        /// </summary>
        /// <param name="sender">Usual sender object received by events</param>
        /// <param name="e">Event arguments received by events</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            if (this._isInitialised && !Page.IsPostBack)
            {
                try
                {
                    this.DataBindExperiments();
                }
                catch (Exception ex)
                {
                    this.HandleException(ex);
                }
            }
        }

        /// <summary>
        /// Dispose, overridden to make sure that the database context is disposed of correctly
        /// </summary>
        public override void Dispose()
        {
            base.Dispose();
            if (this._dbcontext != null)
            {
                this._dbcontext.Connection.Close();
                this._dbcontext.Dispose();
            }
        }
        #endregion

        #region Private helper methods

        /// <summary>
        /// Add controls, scripts and style sheets dynamically not already in markup
        /// </summary>
        private void AddControls()
        {
            //Add stylesheet and javascript controls
            this.Page.AddHDCStylesheet();
            this.Page.AddHDCJQuery(true);
            this.Page.AddHDCJavaScript();

            //Find the experiments quick search box, cast it, and store it in a field
            this._searchControl = this.Control_ExperimentQuickSearch as ExperimentQuickSearch;
        }

        /// <summary>
        /// Setup the event handlers for controls on the page
        /// </summary>
        private void ConfigureEvents()
        {
            this.View_Experiments.RowDataBound += new GridViewRowEventHandler(View_Experiments_RowDataBound);
            this._searchControl.ExperimentSelected += new ExperimentSelectedEventHandler(this.QuickSearchControl_ExperimentSelected);
        }

        /// <summary>
        /// Reports exceptions by adding a new label to top of page
        /// </summary>
        /// <param name="e">The exception to report</param>
        private void HandleException(Exception e)
        {
            HDCSharedWebFunctions.AddErrorLabel("An error occurred: " + e.Message, this.placeholder_ErrorReporting);
            this._isInitialised = false;
        }

        private void QuickSearchControl_ExperimentSelected(object sender, ExperimentSelectedEventArgs e)
        {
            Response.Redirect(HDCConfiguration.GetUrl_ExperimentDetails(e.SelectedExperimentID));
        }

        #endregion

        #region Data binding

        /// <summary>
        /// Data binding experiment grid view - load all experiments and databind them to the gridview
        /// </summary>
        private void DataBindExperiments()
        {
            //Lookup current user
            WindowsIdentity identity = Context.User.Identity as WindowsIdentity;

            IEnumerable<Experiment> usersExperiments = null;

            //Get the user's experiments
            //A WMI Query might be required which needs elevated priveleges
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                usersExperiments = this._dbcontext.GetExperimentsForUser(identity.User, HDCExperimentAccessLevels.ReadOnly).ToList();
            });

            string message = "";
            IQueryable<Experiment> baseExperimentQuery = this._dbcontext.Experiments;
            int totalExperimentCount = usersExperiments.Count();
            if (totalExperimentCount > maximumExperiments)
            {
                //Hide deleted experiments and limit the number of experiments loaded.
                message += string.Format("There are {0} experiments. Deleted experiments have been excluded and we will limit to the first {1}. Please use search functions instead. ", totalExperimentCount, maximumExperiments);
                baseExperimentQuery = baseExperimentQuery.Where(exp=>!exp.IsDeleted || exp.ExperimentType.ID == (int)HDCExperimentTypes.Template).Take(maximumExperiments);
            }

            IEnumerable<GridData> gridData =
                usersExperiments
                //Because we can't include the other tables with a stored procedure in entity framework, load them all again with the joined tables
                .Join(
                    baseExperimentQuery.Select(exp =>
                        new GridData
                        {
                            Experiment = exp,
                            //By loading this now, we can save round trips to the database
                            ExperimentType = exp.ExperimentType,
                            //By loading this now, we can save round trips to the database
                            ExperimentParameters = exp.ExperimentParameters,
                            //By loading this now, we can save round trips to the database
                            DataFileCount = exp.ExperimentDataFiles.Count(),
                            //By loading this now, we can save round trips to the database
                            ParameterCount = exp.ExperimentParameters.Count()
                        }),
                    spexp => spexp.ID,
                    gd => gd.ID,
                    (spexp, gd) => gd
                    )
                .ToList();

            //Report to the user how many experiments we are listing
            message += string.Format("Showing {0} experiments.", gridData.Count());
            HDCSharedWebFunctions.AddErrorLabel(message, placeholder_ErrorReporting);

            //Perform the data bind with the loaded data
            this.View_Experiments.DataSource = gridData;
            this.View_Experiments.DataBind();
        }

        #endregion

        #region View_Experiments Events

        /// <summary>
        /// Called for each row created and used to populate missing data in the row and set CSS styles
        /// </summary>
        /// <param name="sender">Usual sender object received by events</param>
        /// <param name="e">Event arguments received by events</param>
        private void View_Experiments_RowDataBound(object sender, GridViewRowEventArgs e)
        {
            SPGridViewRow gvr = (SPGridViewRow)e.Row;

            if (e.Row.RowIndex >= 0)
            {
                GridData boundExperimentData = e.Row.DataItem as GridData;
                if (boundExperimentData != null)
                {
                    Experiment boundExperiment = boundExperimentData.Experiment;

                    //Set counts and experiment type
                    Label lbl_ExperimentDataFileCount = gvr.FindControl("lbl_ExperimentDataFileCount") as Label;
                    Label lbl_ExperimentParameterCount = gvr.FindControl("lbl_ExperimentParameterCount") as Label;
                    if (lbl_ExperimentDataFileCount != null && lbl_ExperimentParameterCount != null)
                    {
                        lbl_ExperimentDataFileCount.Text = boundExperimentData.DataFileCount.ToString();
                        lbl_ExperimentParameterCount.Text = boundExperimentData.ParameterCount.ToString();
                    }

                    gvr.CssClass = "ExperimentTableRow";

                    //Set style of deleted experiments
                    if (boundExperiment.IsDeleted == true)
                    {
                        gvr.CssClass += " DeletedItem";
                    }
                    else
                    {
                        gvr.CssClass += " NormalItem";
                    }

                    if (boundExperiment.ExperimentType.ID == (int)HDCExperimentTypes.Template)
                    {
                        gvr.CssClass += " HDCExperimentTemplate";
                    }

                    //Set thumbnail link (an IMG tag is added with javascript to prevent the browser locking up when servers are down)
                    HyperLink link_Thumbnail = gvr.FindControl("link_Thumbnail") as HyperLink;
                    if(link_Thumbnail!=null)
                    {
                        string imageUrl = boundExperiment.GetThumbnail(this._dbcontext);
                        if (!string.IsNullOrEmpty(imageUrl))
                        {
                            link_Thumbnail.NavigateUrl = imageUrl;
                        }
                        else
                        {
                            link_Thumbnail.Visible = false;
                        }
                    }
                }
            }
        }


        #endregion

    }
}
